package com.tbynet.jwp.admin.index;

import com.jfinal.aop.Clear;
import com.jfinal.aop.Inject;
import com.jfinal.kit.Ret;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.ehcache.CacheKit;
import com.tbynet.jwp.admin.AdminController;
import com.tbynet.jwp.admin.AdminInterceptor;
import com.tbynet.jwp.framework.kit.IpKit;
import com.tbynet.jwp.service.spi.UserManager;
import com.tbynet.jwp.model.Users;

/**
 * 首页和管理员登录控制器
 *
 * 核心职责：
 * 1. 管理员登录和登出功能
 * 2. 验证码生成和验证
 * 3. 用户注册和密码找回入口
 * 4. 系统缓存管理
 *
 * 设计原则：
 * - 登录相关接口清除权限拦截
 * - 统一的登录验证流程
 * - 安全的会话管理
 * - 完善的错误处理
 *
 * @author 佰亿互联
 * @version 3.0
 * @since 2025-11-04
 */
public class IndexAdminController extends AdminController {

    // ========== 依赖注入 ==========

    /** 用户管理编排层 - 用于处理登录业务逻辑 */
    @Inject
    private UserManager userManager;

    // ========== 页面渲染方法 ==========

    /**
     * 管理员首页
     *
     * 功能说明：
     * - 显示管理员后台首页
     * - 需要管理员登录权限
     * - 加载用户统计信息
     *
     * 访问路径：GET /admin
     */
    public void index() {
        long startTime = System.currentTimeMillis();

        try {
            logOperation("VIEW_HOME", "管理员首页", "开始", null);

            // 验证登录状态
            if (!requireLogin()) {
                return;
            }

            // 加载首页数据
            loadIndexData();

            render("index.html");

            logOperation("VIEW_HOME", "管理员首页", "成功",
                    "用户ID: " + getLoginUser().getID());

        } catch (Exception e) {
            logOperation("VIEW_HOME", "管理员首页", "失败", e.getMessage());
            handleSystemException(e, "加载管理员首页");
        } finally {
            log.debug("首页加载完成，耗时: %sms", System.currentTimeMillis() - startTime);
        }
    }

    /**
     * 生成验证码
     *
     * 功能说明：
     * - 生成登录验证码图片
     * - 清除权限拦截，允许未登录访问
     * - 支持验证码刷新
     *
     * 访问路径：GET /admin/captcha
     */
    @Clear(AdminInterceptor.class)
    public void captcha() {
        try {
            log.debug("生成验证码请求，IP: %s", getRealIp());

            renderCaptcha();

        } catch (Exception e) {
            log.error("生成验证码异常", e);
            renderError(500);
        }
    }

    // ========== 登录登出功能 ==========

    /**
     * 管理员登录
     *
     * 功能说明：
     * - 处理管理员登录请求
     * - 支持GET（显示登录页）和POST（处理登录）
     * - 清除权限拦截，允许未登录访问
     *
     * 访问路径：
     * - GET /admin/login
     * - POST /admin/login
     */
    @Clear(AdminInterceptor.class)
    public void login() {
        String redirectUrl = getPara("redirect_url", "/admin");
        long startTime = System.currentTimeMillis();

        try {
            // GET请求显示登录页面
            if (isGet()) {
                handleGetLogin(redirectUrl);
                return;
            }

            // POST请求处理登录
            handlePostLogin(redirectUrl);

        } catch (Exception e) {
            log.error("登录处理异常", e);
            handleLoginException(redirectUrl, e);
        } finally {
            log.debug("登录处理完成，耗时: %sms", System.currentTimeMillis() - startTime);
        }
    }

    /**
     * 管理员登出
     *
     * 功能说明：
     * - 处理管理员登出请求
     * - 清理会话和Cookie
     * - 重定向到登录页面
     *
     * 访问路径：GET /admin/logout
     */
    public void logout() {
        try {
            Users user = getLoginUser();
            String userId = user != null ? String.valueOf(user.getID()) : "unknown";

            logOperation("LOGOUT", "用户登出", "开始", "用户ID: " + userId);

            // 执行登出操作
            performLogout();

            logOperation("LOGOUT", "用户登出", "成功", "用户ID: " + userId);

            redirect("/admin/login");

        } catch (Exception e) {
            logOperation("LOGOUT", "用户登出", "失败", e.getMessage());
            log.error("管理员登出异常", e);
            redirect("/admin/login");
        }
    }

    /**
     * 登出其他设备
     *
     * 功能说明：
     * - 强制登出当前用户的其他会话
     * - 保持当前会话有效
     * - 增强账户安全性
     *
     * 访问路径：POST /admin/destroy
     */
    public void destroy() {
        try {
            Users user = getLoginUser();
            if (user == null) {
                fail("用户未登录");
                return;
            }

            logOperation("LOGOUT_OTHER_DEVICES", "登出其他设备", "开始",
                    "用户ID: " + user.getID());

            String sessionId = getSessionId(Users.sessionIdName);
            Ret result = userManager.destroyOtherSessions(sessionId);
            if (result.isOk()) {
                logOperation("LOGOUT_OTHER_DEVICES", "登出其他设备", "成功",
                        "用户ID: " + user.getID());
                ok(Ret.by("msg", "登出其他设备成功"));
            } else {
                logOperation("LOGOUT_OTHER_DEVICES", "登出其他设备", "失败",
                        "用户ID: " + user.getID());
                fail("登出其他设备失败，请联系管理员");
            }

        } catch (Exception e) {
            logOperation("LOGOUT_OTHER_DEVICES", "登出其他设备", "异常", e.getMessage());
            handleSystemException(e, "登出其他设备");
        }
    }

    // ========== 注册和密码找回 ==========

    /**
     * 用户注册入口
     *
     * 功能说明：
     * - 显示用户注册页面
     * - 处理注册验证码验证
     * - 清除权限拦截，允许未登录访问
     *
     * 访问路径：
     * - GET /admin/register
     * - POST /admin/register
     */
    @Clear(AdminInterceptor.class)
    public void register() {
        try {
            if (isGet()) {
                render("register.html");
                return;
            }

            handlePostRegister();

        } catch (Exception e) {
            log.error("用户注册处理异常", e);
            fail("注册处理失败，请稍后重试");
        }
    }

    /**
     * 密码找回入口
     *
     * 功能说明：
     * - 显示密码找回页面
     * - 处理找回密码验证码验证
     * - 清除权限拦截，允许未登录访问
     *
     * 访问路径：
     * - GET /admin/forget
     * - POST /admin/forget
     */
    @Clear(AdminInterceptor.class)
    public void forget() {
        try {
            if (isGet()) {
                render("forget.html");
                return;
            }

            handlePostForget();

        } catch (Exception e) {
            log.error("密码找回处理异常", e);
            fail("密码找回处理失败，请稍后重试");
        }
    }

    // ========== 系统管理功能 ==========

    /**
     * 清理用户缓存
     *
     * 功能说明：
     * - 清理所有登录用户缓存
     * - 用于系统维护和调试
     * - 清除权限拦截，允许未登录访问
     *
     * 访问路径：GET /admin/clear
     */
    @Clear(AdminInterceptor.class)
    public void clear() {
        try {
            logOperation("CLEAR_CACHE", "清理用户缓存", "开始", null);

            CacheKit.removeAll(Users.loginUserCacheName);

            logOperation("CLEAR_CACHE", "清理用户缓存", "成功", null);
            renderNull();

        } catch (Exception e) {
            logOperation("CLEAR_CACHE", "清理用户缓存", "失败", e.getMessage());
            log.error("清理用户缓存异常", e);
            renderError(500);
        }
    }

    // ========== 私有方法：登录处理 ==========

    /**
     * 处理GET登录请求
     */
    private void handleGetLogin(String redirectUrl) {
        // 清除现有会话
        String sessionId = getSessionId(Users.sessionIdName);
        if (StrKit.notBlank(sessionId)) {
            userManager.logout(sessionId);
            removeSessionId(Users.sessionIdName);
        }

        set("redirectUrl", redirectUrl);
        render("login.html");
    }

    /**
     * 处理POST登录请求
     */
    private void handlePostLogin(String redirectUrl) {
        // 获取请求参数
        String username = getPara("username");
        String password = getPara("password");
        String vcode = getPara("vcode");
        boolean keepLogin = getParaToBoolean("rememberme", false);

        // 参数验证
        if (!validateLoginParams(username, password, vcode)) {
            return;
        }

        // 验证码验证
        if (!validateCaptcha("vcode")) {
            fail("验证码不正确");
            return;
        }

        // 调用Manager层进行登录
        String loginIp = IpKit.getRealIp(getRequest());
        Ret ret = userManager.login(username, password, keepLogin, loginIp, getUserAgent());

        if (ret.isOk()) {
            // 登录成功，设置cookie
            handleLoginSuccess(ret, redirectUrl, username, loginIp);
        } else {
            handleLoginFailure(ret, username, loginIp);
        }
    }

    /**
     * 处理登录成功
     */
    private void handleLoginSuccess(Ret ret, String redirectUrl, String username, String loginIp) {
        String sessionId = ret.getStr(Users.sessionIdName);
        int maxAgeInSeconds = ret.getAs("maxAgeInSeconds");

        setSessionId(Users.sessionIdName, sessionId, maxAgeInSeconds);
        setAttr(Users.loginUserCacheName, ret.get(Users.loginUserCacheName));

        ret.set("redirectUrl", redirectUrl);

        logOperation("LOGIN", "用户登录", "成功",
                "用户名: " + hideSensitiveInfo(username, 2, 2) + ", IP: " + loginIp);

        json(ret);
    }

    /**
     * 处理登录失败
     */
    private void handleLoginFailure(Ret ret, String username, String loginIp) {
        logOperation("LOGIN", "用户登录", "失败",
                "用户名: " + hideSensitiveInfo(username, 2, 2) + ", IP: " + loginIp +
                        ", 原因: " + ret.getStr("msg"));

        json(ret);
    }

    /**
     * 处理登录异常
     */
    private void handleLoginException(String redirectUrl, Exception e) {
        log.error("登录处理异常，重定向URL: %s", redirectUrl, e);
        fail("登录处理失败，请稍后重试");
    }

    // ========== 私有方法：登出处理 ==========

    /**
     * 执行登出操作
     */
    private void performLogout() {
        String sessionId = getSessionId(Users.sessionIdName);
        removeSessionId(Users.sessionIdName);
        userManager.logout(sessionId);
    }

    // ========== 私有方法：注册和密码找回处理 ==========

    /**
     * 处理POST注册请求
     */
    private void handlePostRegister() {
        String username = getPara("username");
        String vcode = getPara("vcode");

        // 参数验证
        if (!validateRegisterParams(username, vcode)) {
            return;
        }

        // 验证码验证
        if (!validateCaptcha("vcode")) {
            fail("验证码不正确");
            return;
        }

        ok(Ret.by("msg", "发送成功"));
    }

    /**
     * 处理POST密码找回请求
     */
    private void handlePostForget() {
        String username = getPara("username");
        String vcode = getPara("vcode");

        // 参数验证
        if (!validateForgetParams(username, vcode)) {
            return;
        }

        // 验证码验证
        if (!validateCaptcha("vcode")) {
            fail("验证码不正确");
            return;
        }

        ok(Ret.by("msg", "发送成功"));
    }

    // ========== 私有方法：参数验证 ==========

    /**
     * 验证登录参数
     */
    private boolean validateLoginParams(String username, String password, String vcode) {
        if (!validateRequired("username", "用户名")) return false;
        if (!validateRequired("password", "密码")) return false;
        if (!validateRequired("vcode", "验证码")) return false;
        if (!validateLength(username, 3, 50, "用户名")) return false;
        if (!validateLength(password, 6, 100, "密码")) return false;
        return true;
    }

    /**
     * 验证注册参数
     */
    private boolean validateRegisterParams(String username, String vcode) {
        if (!validateRequired("username", "用户名")) return false;
        if (!validateRequired("vcode", "验证码")) return false;
        if (!validateLength(username, 3, 50, "用户名")) return false;
        return true;
    }

    /**
     * 验证密码找回参数
     */
    private boolean validateForgetParams(String username, String vcode) {
        if (!validateRequired("username", "用户名")) return false;
        if (!validateRequired("vcode", "验证码")) return false;
        if (!validateLength(username, 3, 50, "用户名")) return false;
        return true;
    }

    // ========== 私有方法：数据加载 ==========

    /**
     * 加载首页数据
     */
    private void loadIndexData() {
        // TODO: 加载首页需要的数据，如用户统计、系统信息等

        Users user = getLoginUser();
        set("user", user);
        set("loginTime", new java.util.Date());
        set("clientInfo", getClientInfo());
    }
}